#include <core/file.h>
namespace Core
{
    namespace
    {
        DWORD FileAccess(File::OpenMode mode)
        {
            DWORD fileAccess = 0;
            if (mode & File::ReadOnly)
                fileAccess |= GENERIC_READ;

            if (mode & File::WriteOnly)
                fileAccess |= GENERIC_WRITE;

            return fileAccess;
        }

        DWORD CreationAccess(File::OpenMode mode)
        {
            DWORD creationAccess = 0;

            if (mode & File::Truncate)
                creationAccess = CREATE_ALWAYS;

            if (mode & File::ReadOnly)
                creationAccess = OPEN_EXISTING;

            if (mode & File::WriteOnly)
                creationAccess = OPEN_ALWAYS;

            return creationAccess;
        }
    }

    File::File() : m_openMode(Invalid), m_file(0)
    {

    }

    File::~File()
    {
        close();
    }

    void File::close()
    {
        if (m_file != 0)
        {
            CloseHandle(m_file);
        }
        m_file = 0;
    }

    bool File::open(OpenMode mode, const String& fileName)
    {
        DWORD desiredAccess = FileAccess(mode);
        DWORD creationAccess = CreationAccess(mode);
        m_file = CreateFileW(fileName.c_str(), desiredAccess, 0, 0,
                                  creationAccess, FILE_FLAG_RANDOM_ACCESS, 0);
        if (m_file == INVALID_HANDLE_VALUE)
        {
            return false;
        }
        m_openMode = mode;
        m_fileName = fileName;
        return true;
    }
    
    bool File::isValid() const
    {
        return m_file != INVALID_HANDLE_VALUE;
    }

    bool File::write(const Byte* data, ULong szInBytes)
    {
        if (isValid())
        {
            ULong written = -1;
            BOOL result = WriteFile(m_file, data, szInBytes, reinterpret_cast<DWORD*>(&written), 0);
            if (!result || written < szInBytes)
            {
                return false;
            }
            return true;
        }
        return false;
    }

    bool File::read(Byte* inData, ULong szInBytes)
    {
        return false;
    }

    void File::flush()
    {
        if (isValid())
        {
            FlushFileBuffers(m_file);
        }
    }

    bool File::isReadable() const
    {
        return m_openMode & ReadOnly;
    }

    bool File::isWriteable() const
    {
        return m_openMode & WriteOnly;
    }
}